package com.taobao.tddl.common.utils;

import java.util.Date;

/**
 * mysql中将string转化为date的代码
 * 
 * @since 5.0.0
 */
public class DateUtils {

    public static final int TIME_DATETIME_ONLY          = 0;
    public static int       internal_format_positions[] = { 0, 1, 2, 3, 4, 5, 6, 255 };
    public static final int MAX_DATE_PARTS              = 8;
    // long log_10_int[] = new long[] { 1, 10, 100, 1000, 10000L, 100000L,
    // 1000000L, 10000000L, 100000000L };
    public static final int YY_PART_YEAR                = 70;

    @SuppressWarnings({ "deprecation", "unused" })
    public static Date str_to_time(String str) {
        int length = str.length();
        int was_cut;
        Date time = new Date(0);
        int field_length;
        int digits;
        int year_length = 0;
        int add_hours = 0, start_loop;
        long not_zero_date, allow_space;
        boolean is_internal_format;
        int pos;
        int last_field_pos = 0;
        int cur_pos = 0;
        int i;
        int date[] = new int[MAX_DATE_PARTS];
        int date_len[] = new int[MAX_DATE_PARTS];
        int number_of_fields;
        boolean found_delimitier = false, found_space = false;
        int frac_pos;
        int frac_len;
        // DBUG_ENTER("str_to_datetime");
        // DBUG_PRINT("ENTER",("str: %.*s",length,str));
        //
        // LINT_INIT(field_length);

        was_cut = 0;

        /* Skip space at start */
        str = str.trim();
        // for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
        // ;
        int end = str.length();
        if (str.isEmpty() || !isdigit(str.charAt(0))) {
            was_cut = 1;
            return null;
        }
        // if (str == end || ! my_isdigit(&my_charset_latin1, *str))
        // {
        // *was_cut= 1;
        // DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
        // }

        is_internal_format = false;
        /*
         * This has to be changed if want to activate different timestamp
         * formats
         */
        int format_position[] = internal_format_positions;

        /*
         * Calculate number of digits in first part. If length= 8 or >= 14 then
         * year is of format YYYY. (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS)
         */

        for (pos = 0; pos < str.length() && (isdigit(str.charAt(pos)) || str.charAt(pos) == 'T'); pos++)
            ;

        // for (pos=str;
        // pos != end && (my_isdigit(&my_charset_latin1,*pos) || *pos == 'T');
        // pos++)
        // ;

        digits = pos;
        // digits= (uint) (pos-str);
        start_loop = 0; /* Start of scan loop */
        date_len[format_position[0]] = 0; /* Length of year field */

        if (pos == str.length() || str.charAt(pos) == '.') {
            /* Found date in internal format (only numbers like YYYYMMDD) */
            year_length = (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
            field_length = year_length;
            is_internal_format = true;
            format_position = internal_format_positions;
        } else {
            if (format_position[0] >= 3) /* If year is after HHMMDD */
            {
                /*
                 * If year is not in first part then we have to determinate if
                 * we got a date field or a datetime field. We do this by
                 * checking if there is two numbers separated by space in the
                 * input.
                 */
                while (pos < end && !my_isspace(str.charAt(pos)))
                    pos++;
                while (pos < end && !isdigit(str.charAt(pos)))
                    pos++;
                if (pos == end) {
                    /* Date field. Set hour, minutes and seconds to 0 */
                    date[0] = date[1] = date[2] = date[3] = date[4] = 0;
                    start_loop = 5; /* Start with first date part */
                }
            }

            field_length = format_position[0] == 0 ? 4 : 2;
        }

        // if (pos == end || *pos == '.')
        // {
        // /* Found date in internal format (only numbers like YYYYMMDD) */
        // year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
        // field_length= year_length;
        // is_internal_format=true;
        // format_position= internal_format_positions;
        // }
        // else
        // {
        // if (format_position[0] >= 3) /* If year is after HHMMDD */
        // {
        // /*
        // If year is not in first part then we have to determinate if we got
        // a date field or a datetime field.
        // We do this by checking if there is two numbers separated by
        // space in the input.
        // */
        // while (pos < end && !my_isspace(&my_charset_latin1, *pos))
        // pos++;
        // while (pos < end && !my_isdigit(&my_charset_latin1, *pos))
        // pos++;
        // if (pos == end)
        // {
        // if (flags & TIME_DATETIME_ONLY)
        // {
        // *was_cut= 1;
        // DBUG_RETURN(MYSQL_TIMESTAMP_NONE); /* Can't be a full datetime */
        // }
        // /* Date field. Set hour, minutes and seconds to 0 */
        // date[0]= date[1]= date[2]= date[3]= date[4]= 0;
        // start_loop= 5; /* Start with first date part */
        // }
        // }
        //
        // field_length= format_position[0] == 0 ? 4 : 2;
        // }

        /*
         * Only allow space in the first "part" of the datetime field and: -
         * after days, part seconds - before and after AM/PM (handled by code
         * later) 2003-03-03 20:00:20 AM 20:00:20.000000 AM 03-03-2000
         */
        i = max(format_position[0], format_position[1]);

        if (i < format_position[2]) i = format_position[2];
        // set_if_bigger(i,format_position[2]);
        allow_space = ((1 << i) | (1 << format_position[6]));
        allow_space &= (1 | 2 | 4 | 8);

        not_zero_date = 0;
        for (i = start_loop; i < MAX_DATE_PARTS - 1 && cur_pos != end && isdigit(str.charAt(cur_pos)); i++) {
            int start = cur_pos;
            int tmp_value = (str.charAt(cur_pos++) - '0');

            /*
             * Internal format means no delimiters; every field has a fixed
             * width. Otherwise, we scan until we find a delimiter and discard
             * leading zeroes -- except for the microsecond part, where leading
             * zeroes are significant, and where we never process more than six
             * digits.
             */
            boolean scan_until_delim = !is_internal_format && ((i != format_position[6]));

            while (cur_pos != end && isdigit(str.charAt(cur_pos)) && (scan_until_delim || (--field_length != 0))) {
                tmp_value = tmp_value * 10 + (str.charAt(cur_pos) - '0');
                cur_pos++;
            }
            date_len[i] = (cur_pos - start);
            if (tmp_value > 999999) /* Impossible date part */
            {
                was_cut = 1;
                return null;
            }
            date[i] = tmp_value;
            not_zero_date |= tmp_value;

            /* Length of next field */
            field_length = format_position[i + 1] == 0 ? 4 : 2;

            if ((last_field_pos = cur_pos) == end) {
                i++; /* Register last found part */
                break;
            }
            /* Allow a 'T' after day to allow CCYYMMDDT type of fields */
            if (i == format_position[2] && str.charAt(cur_pos) == 'T') {
                cur_pos++; /* ISO8601: CCYYMMDDThhmmss */
                continue;
            }
            if (i == format_position[5]) /* Seconds */
            {
                if (str.charAt(cur_pos) == '.') /* Followed by part seconds */
                {
                    cur_pos++;
                    field_length = 6; /* 6 digits */
                }
                continue;
            }
            while (cur_pos != end && (my_ispunct(str.charAt(cur_pos)) || my_isspace(str.charAt(cur_pos)))) {
                if (my_isspace(str.charAt(cur_pos))) {
                    if (!((allow_space & (1 << i)) != 0)) {
                        was_cut = 1;
                        return null;
                    }
                    found_space = true;
                }
                cur_pos++;
                found_delimitier = true; /* Should be a 'normal' date */
            }
            /* Check if next position is AM/PM */
            if (i == format_position[6]) /* Seconds, time for AM/PM */
            {
                i++; /* Skip AM/PM part */
                if (format_position[7] != 255) /* If using AM/PM */
                {
                    if (cur_pos + 2 <= end && (str.charAt(cur_pos + 1) == 'M' || str.charAt(cur_pos) + 1 == 'm')) {
                        if (str.charAt(cur_pos) == 'p' || str.charAt(cur_pos) == 'P') add_hours = 12;
                        else if (str.charAt(cur_pos) != 'a' || str.charAt(cur_pos) != 'A') continue; /*
                                                                                                      * Not
                                                                                                      * AM
                                                                                                      * /
                                                                                                      * PM
                                                                                                      */
                        str += 2; /* Skip AM/PM */
                        /* Skip space after AM/PM */
                        while (cur_pos != end && my_isspace(str.charAt(cur_pos)))
                            cur_pos++;
                    }
                }
            }
            last_field_pos = cur_pos;
        }
        // if (found_delimitier && !found_space
        // && ((flags & TIME_DATETIME_ONLY) != 0)) {
        // was_cut = 1;
        // return null; /* Can't be a datetime */
        // }

        cur_pos = last_field_pos;

        number_of_fields = i - start_loop;
        while (i < MAX_DATE_PARTS) {
            date_len[i] = 0;
            date[i++] = 0;
        }

        if (!is_internal_format) {
            year_length = date_len[format_position[0]];
            if (!(year_length != 0)) /* Year must be specified */
            {
                was_cut = 1;
                return null;
            }
            time.setYear(date[format_position[0]] - 1900);
            // l_time->year= date[(uint) format_position[0]];
            time.setMonth(date[format_position[1]] - 1);
            // l_time->month= date[(uint) format_position[1]];
            time.setDate(date[format_position[2]]);
            // l_time->day= date[(uint) format_position[2]];
            time.setHours(date[format_position[3]]);
            time.setMinutes(date[format_position[4]]);
            time.setSeconds(date[format_position[5]]);
            // l_time->hour= date[(uint) format_position[3]];
            // l_time->minute= date[(uint) format_position[4]];
            // l_time->second= date[(uint) format_position[5]];

            frac_pos = format_position[6];
            frac_len = date_len[frac_pos];
            // if (frac_len < 6)
            // date[frac_pos]*= log_10_int[6 - frac_len];
            // l_time->second_part= date[frac_pos];

            if (format_position[7] != 255) {
                if (time.getHours() > 12) {
                    was_cut = 1;
                    return null;
                }
                time.setHours(time.getHours() % 12 + add_hours);
            }
        } else {
            time.setYear(date[0] - 1900);
            time.setMonth(date[1] - 1);
            time.setDate(date[2]);
            time.setHours(date[3]);
            time.setMinutes(date[4]);
            time.setSeconds(date[5]);
            // if (date_len[6] < 6)
            // date[6]*= log_10_int[6 - date_len[6]];
            // l_time->second_part=date[6];
        }
        // l_time->neg= 0;

        if (year_length == 2 && (not_zero_date != 0)) time.setYear(time.getYear()
                                                                   + (time.getYear() < YY_PART_YEAR ? 2000 : 1900));
        // l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);

        if (number_of_fields < 3 || time.getYear() > 9999 || time.getMonth() > 12 || time.getDate() > 31
            || time.getHours() > 23 || time.getMinutes() > 59 || time.getMinutes() > 59) {
            /* Only give warning for a zero date if there is some garbage after */
            if (!(not_zero_date != 0)) /* If zero date */
            {
                for (; cur_pos != end; cur_pos++) {
                    if (!my_isspace(str.charAt(cur_pos))) {
                        not_zero_date = 1; /* Give warning */
                        break;
                    }
                }
            }
            // was_cut= test(not_zero_date);
            return null;
        }

        if (check_date(time, not_zero_date != 0, was_cut)) return null;

        // l_time->time_type= (number_of_fields <= 3 ?
        // MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);

        for (; cur_pos != end; cur_pos++) {
            if (!my_isspace(str.charAt(cur_pos))) {
                was_cut = 1;
                break;
            }
        }

        return time;
    }

    public static boolean check_date(Date time, boolean not_zero_date, int was_cut) {
        return false;
    }

    public static boolean my_ispunct(char v) {
        switch (Character.getType(v)) {
            case Character.CONNECTOR_PUNCTUATION:
            case Character.DASH_PUNCTUATION:
            case Character.END_PUNCTUATION:
            case Character.FINAL_QUOTE_PUNCTUATION:
            case Character.INITIAL_QUOTE_PUNCTUATION:
            case Character.START_PUNCTUATION:
            case Character.OTHER_PUNCTUATION:
                return true;
        }

        return false;
    }

    public static int max(int i, int j) {
        return i > j ? i : j;
    }

    public static boolean my_isspace(char v) {
        return Character.isWhitespace(v);
    }

    public static boolean isdigit(char v) {
        return Character.isDigit(v);
    }
}
